﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Threading;

namespace SimpleEntry
{
	public class DateConverter : IConverter
	{
		////////////////////////////////////////////////////////
		// Interface. Delegate to internal overridable mothoes
		public String Format(object o) { return internalFormat(o); }

		public object Parse(String value, out String parseErrorMessage) { return internalParse(value,  out parseErrorMessage); }

		//public bool Validate(object o, out String errorMessage) { return internalValidate(o, out errorMessage); }

		////////////////////////////////////////////////////////
	
		// speciaised interface
		[Flags]
		// Vanilla date only. DateAndTime = allow time entry
		public enum flags {Vanilla = 0, DateAndTime = 1}

		//////////// Constructors//////////////////////////////////
		//
		// simplest version. Same as VanillaIntegerConverter
		public DateConverter()
			{ init(flags.Vanilla); }

		// allows formatting with commas and preventing negative or zero values.
		public DateConverter(flags flagsIn)
			{ init(flagsIn); }

		// 
		///////////////////////////////////////////////////////////

		private void init(flags flagsIn)
		{
			this.m_Flags = flagsIn;
		}

		private string internalFormat(object o)
		{
			// deal with empty case
			if (IsObjectNull(o)) return "";

			// this may throw, but I can't think what to do with it if I catch it here
			// so we'll let it propagate.
			DateTime dt = (DateTime)o;

			// date time wanted
			if ((this.m_Flags & flags.DateAndTime) == flags.DateAndTime)
				return dt.ToShortDateString() + " " + dt.ToLongTimeString();
			
			// otherwise not time element
			return dt.ToShortDateString();
		}

		private object internalParse(String value, out String parseErrorMessage)
		{
			parseErrorMessage = "";

			if (value.Trim().Length == 0) return System.DBNull.Value;

			// delegate to .NET date validation
			DateTime dt;
			if (DateTime.TryParse(value, out dt))
				return dt;

			// error
			parseErrorMessage = String.Format(DATE_PARSE_ERROR, GetRequiredDateFormat());
			return null;
		}

		bool IsObjectNull(object o)
		{
			if (o == null) return true;
			if (o.GetType() == typeof(System.DBNull)) return true;
			return false;
		}

		String GetRequiredDateFormat()
		{
			DateTimeFormatInfo format = Thread.CurrentThread.CurrentCulture.DateTimeFormat; 
			if ((this.m_Flags & flags.DateAndTime) == flags.DateAndTime)
				return format.ShortDatePattern+ " " + format.LongTimePattern;
			return format.ShortDatePattern;
		}

		flags m_Flags;

		const String DATE_PARSE_ERROR = @"
Incorrect format for a Date or invalid day, month or year value.
Expected format is: {0}
";
	}
}
